#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include "Log.hpp"
#include "Thread.hpp"
#include "Cond.hpp"
#include "Mutex.hpp"

using namespace std;
namespace ThreadPoolModule
{
   using namespace ThreadModule;
   using namespace LogModule;
   using namespace CondModule;
   using namespace MutexModule;
   using LogModule::Logger;
   using ThreadModule::Thread;
   static const int gnum = 5;
   template <class T>
   class ThreadPool
   {
   private:
      void WakeUpAllThread()
      {
         LockGuard lockguard(_mutex);
         if (_sleepernum)
            _cond.Broadcast();
         LOG(LogLevel::INFO) << "唤醒所有的休眠线程";
      }
      void WakeUpOne()
      {
         _cond.Signal();
         LOG(LogLevel::INFO) << "唤醒一个休眠线程";
      }

      ThreadPool(int num = gnum) : _num(num), _isrunning(false), _sleepernum(0)
      {
         for (int i = 0; i < num; i++)
         {
            _threads.emplace_back(
                [this]()
                {
                   HandlerTask();
                });
         }
      } 
      void Start()
      {
         if (_isrunning)
            return;
            _isrunning=true;
         LOG(LogLevel::DEBUG) << "获取单例。。。";
         for (auto &thread : _threads)
         {
            thread.Start();
            LOG(LogLevel::INFO) << "start new thread success: " <<thread.Name();
         }
      }
      ThreadPool(const ThreadPool<T> &) = delete;
      ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

   public:
      static ThreadPool<T> *GetInstance()
      {
         if (inc == nullptr)
         {
            LockGuard lockguard(_lock);
            LOG(LogLevel::DEBUG) << "获取单例.....";
            if (inc == nullptr)
            {
               LOG(LogLevel::DEBUG) << "首次使用单例，创建一下";
               inc = new ThreadPool<T>();
               inc->Start();
            }
         }
         return inc;
      }
      void Join()
      {
         for (auto &thread : _threads)
         {
            thread.Join();
         }
      }
      void HandlerTask()
      {
         char name[128];
         pthread_getname_np(pthread_self(), name, sizeof(name));
         while (1)
         {
            T t;
            {
               LockGuard lockguard(_mutex);
               while (_taskq.empty() && _isrunning)
               {
                  _sleepernum++;
                  _cond.Wait(_mutex);
                  _sleepernum--;
               }
               if (!_isrunning && _taskq.empty())
               {
                  LOG(LogLevel::INFO) << name << "退出了，线程池退出了&&任务队列为空";
                  break;
               }
               t = _taskq.front();
               _taskq.pop();
            }
            t();
         }
      }
      bool Enqueue(const T &in)
      {
         if (_isrunning)
         {
            LockGuard lockguard(_mutex);
            _taskq.push(in);
            if (_threads.size() == _sleepernum)
               WakeUpOne();
            return true;
         }
         return false;
      }

   private:
      vector<Thread> _threads;
      int _num;
      queue<T> _taskq;
      Cond _cond;
      Mutex _mutex;
      bool _isrunning;
      int _sleepernum;
      // bug??
      static ThreadPool<T>* inc; // 单例指针
      static Mutex _lock;
   };
   template<class T>
   ThreadPool<T>* ThreadPool<T>::inc=nullptr;
   template <typename T>
    MutexModule::Mutex ThreadPool<T>::_lock;
}